package com.apttbc.looneytuner;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.DoubleBuffer;

import android.os.Environment;

import edu.emory.mathcs.jtransforms.fft.DoubleFFT_1D;

/**
 * Class to analyze raw audio data using FFT
 * @author aptbosox
 *
 */
class SoundDataUtils {
	private final String AUDIO_RECORDER_FOLDER = "AudioRecorder";
	
	private byte [] audioBytes;
	private double [] audioDbl;
	private DoubleFFT_1D fftModule;
	private int bufferSize;
	private double primaryFreq;
	private double fundFreq;
	private double magnitude;
	
	/**
	 * Create a new SoundDataUtils object with the given input audio bytes
	 * @param audioBytes the audio data to analyze
	 */
	public SoundDataUtils(byte[] audioBytes){
		this.audioBytes = audioBytes;
		bufferSize = audioBytes.length / 2;
	    audioDbl = new double[bufferSize];
	    fftModule = new DoubleFFT_1D(bufferSize);
	    fundFreq = 1.0 * Audible.SAMPLE_RATE / bufferSize;
	}
	
	
	/**
	 * Convert the byte array to a double array
	 */
	private void pcmToDouble() {
	    ByteBuffer byteBuf = ByteBuffer.wrap(audioBytes);
	    byteBuf.order(ByteOrder.LITTLE_ENDIAN);
	    double scalingFactor = 1 / 32768.0;
//	    double scalingFactor = 1.0;
	    for (int i = 0; i < bufferSize; i++) {
	        double mono = (double) byteBuf.getShort();
	        audioDbl[i] = mono * scalingFactor;
	    }
	}
	
	/**
	 * Perform the FFT on the double array using the DoubleFFT_1D class
	 */
	public void transformData(){
		fftModule.realForward(audioDbl);
	}
	
	private void calcFrequency() {
		int k = 1;
		int bigK = 1;
		double re = 0;
		double im = 0;
		double mag = 0;
		double bigMag = 0;
		DoubleBuffer theBuf = DoubleBuffer.wrap(audioDbl);
		theBuf.get();
		theBuf.get();
		while (theBuf.hasRemaining()) {
			re = theBuf.get();
			if (theBuf.hasRemaining()) {
				im = theBuf.get();
			}
			mag = Math.sqrt(Math.pow(re, 2) + Math.pow(im, 2));
			if (mag > bigMag) {
				bigK = k;
				bigMag = mag;
			}
			k++;
		}
		primaryFreq = fundFreq * bigK;
		magnitude = bigMag;
	}

	public double getPrimaryFreq() {
		pcmToDouble();
		transformData();
		calcFrequency();
		return primaryFreq;
	}
	
	public double getMagnitude(){
		return magnitude;
	}
	
	/**
	 * @return the audioBytes
	 */
	public byte[] getAudioBytes() {
		return audioBytes;
	}


	/**
	 * @return the audioDbl
	 */
	public double[] getAudioDbl() {
		return audioDbl;
	}


	/**
	 * @return the bufferSize
	 */
	public int getBufferSize() {
		return bufferSize;
	}
	
	public void writeAudioToFile(){
		String sdPath = Environment.getExternalStorageDirectory().getPath();
        File file = new File(sdPath,AUDIO_RECORDER_FOLDER);
        if(!file.exists())
        	file.mkdir();
        
        String dblFilename = file.getAbsolutePath() + "/output.txt";
        
        File dblFile =  new File(dblFilename);
        
        try {
			FileOutputStream output = new FileOutputStream(dblFile);
			OutputStreamWriter writer = new OutputStreamWriter(output, "US-ASCII");
			for (int i = 0; i < audioDbl.length; i++){
				if(Double.compare(audioDbl[i], 0.0) != 0){
					writer.write(String.valueOf(audioDbl[i]) + "\n");
				}
			}
			
			writer.close();
			output.close();
		} catch (IOException e) {					
			e.printStackTrace();
		}
	}
}